package data

import (
	"context"
	"time"

	"gitee.com/shuokeyun/item-service/internal/data/ent"
	"gitee.com/shuokeyun/item-service/internal/data/ent/item"
	"gitee.com/shuokeyun/item-service/internal/domain"
	"gitee.com/shuokeyun/kratos/errors"
)

type itemRepo struct {
	client *ent.Client
	item   *ent.ItemClient
}

func NewItemRepo(client *ent.Client) domain.ItemRepo {
	return &itemRepo{
		client: client,
		item:   client.Item,
	}
}

// ListItems .
func (o *itemRepo) ListItems(ctx context.Context, search *domain.SearchItemList) (re []*domain.Item, total int32, err error) {
	query := o.client.Item.Query()
	if search.Brand > 0 {
		query.Where(item.Brand(search.Brand))
	}
	if search.PriceArea > 0 {
		query.Where(item.PriceArea(search.PriceArea))
	}
	if search.Status > 0 {
		query.Where(item.Status(search.Status))
	}
	n, err := query.Count(ctx)
	if err != nil {
		err = errors.ErrorDBWrap(err, "select error")
		return
	}
	if n == 0 {
		return
	}
	offset := (search.PageNo - 1) * search.PageSize
	if offset >= int32(n) {
		return
	}
	total = int32(n)
	list, err := query.Offset(int(offset)).Limit(int(search.PageSize)).All(ctx)
	if err != nil {
		err = errors.ErrorDBWrap(err, "select error")
		return
	}
	re = make([]*domain.Item, len(list))
	for k, v := range list {
		re[k] = poConvDo(v)
	}
	return
}

// GetItem .
func (o *itemRepo) GetItem(ctx context.Context, code string, brand, priceArea int32, fields []string) (do *domain.Item, err error) {
	po, err := o.item.Query().Where(item.Code(code)).
		Where(item.Brand(brand)).Where(item.PriceArea(priceArea)).Where(item.Status(1)).
		Select(fields...).Only(ctx)
	if err != nil {
		if ent.IsNotFound(err) {
			return nil, errors.ErrorRecordNotFound("item code %s not fund", code)
		}
		return nil, errors.ErrorDBWrap(err, "select item error")
	}
	return poConvDo(po), nil
}

// CreateItem .
func (o *itemRepo) CreateItem(ctx context.Context, do *domain.Item) (*domain.Item, error) {
	now := time.Now()
	po, err := o.item.Create().SetCode(do.Code).
		SetName(do.Name).SetFullName(do.FullName).SetPriceArea(do.PriceArea).
		SetBrand(do.Brand).SetStatus(do.Status).SetMarketPrice(do.MarketPrice).
		SetCostPrice(do.CostPrice).SetCustomCombo(do.CustomCombo).SetCanSeparate(do.CanSeparate).
		SetCheckedWithItem(do.CheckedWithItem).SetSexLimit(do.SexLimit).SetChildItem(do.ChildItem).
		SetRejectItem(do.RejectItem).SetTestQtyDesc(do.TestQtyDesc).SetTestQty(do.TestQty).
		SetStorageCondition(do.StorageCondition).SetTestMethod(do.TestMethod).SetReportTimeDesc(do.ReportTimeDesc).
		SetConsumable(do.Consumable).SetEmptyStomach(do.EmptyStomach).SetSignificance(do.Significance).
		SetCategoryID(do.CategoryId).SetCreatedAt(now).SetUpdatedAt(now).Save(ctx)
	if err != nil {
		return nil, errors.ErrorDBWrap(err, "save error")
	}
	return poConvDo(po), nil
}

// UpdateItem .
func (o *itemRepo) UpdateItem(ctx context.Context, do *domain.Item, mask []string) (re *domain.Item, err error) {
	return nil, nil
}

// DeleteItem .
func (o *itemRepo) DeleteItem(ctx context.Context, code string, brand, priceArea int32) error {
	return nil
}

// GetItems .
func (o *itemRepo) GetItems(ctx context.Context, code []string, brand, priceArea int32, fields []string) (do []*domain.Item, err error) {
	list, err := o.item.Query().Where(item.CodeIn(code...)).
		Where(item.Brand(brand)).Where(item.PriceArea(priceArea)).Where(item.Status(1)).
		Select(fields...).All(ctx)
	if err != nil {
		return nil, errors.ErrorDBWrap(err, "select error")
	}
	re := make([]*domain.Item, len(list))
	for k, v := range list {
		re[k] = poConvDo(v)
	}
	return re, nil
}
